by Per Finander
e-mail:pfimdt93@hvdc.hv.se

TI85/TI82 link-protocol
-----------------------

The linkinterface uses 2 outputs (RTS/DTR) and 2 inputs (CTS/DSR) on the
serial port to communicate with the TI85/TI82. The bits CTS/DSR can be
read from port $3F8+6, bit 4 (CTS) and bit 5 (DSR). The bits RTS/DTR is
controlled from port $3F8+4, bit 0 (DTR) and bit 1 (RTS). $3F8 is the port-
address for COM1: (or $2F8 if COM2: is used).

I've included 5 routines in Pascal to show how to send/receive bytes to/from
the TI85/TI82. These routines are not optimized and doesn't contain any
timeout check. The constant "PortAddr" contains the base-port address to the
com-port. PortAddr=$3F8 if the link-interface is in COM1: or $2F8 if COM2: is
used. The "InitPort" procedure must be called as fast as possible, because
if CTS & DSR isn't set, then the calculator will slow down when the link
is connected.


All data is sent in packages. A packet looks like this:

ID From: $85=TI85 ($82=TI82), $05 (Computer communicating with TI85) /
|                             $02 (Computer communicating with TI82)
|
|   Command:  $06 : Variable-header (used to initiate a variabletransmission)
|   |         $15 : Data part (the datapart of a variable)
|   |         $36 : Answer skip/abort
|   |         $56 : Package received OK (used to acknowledge a package)
|   |         $92 : No more variables to send (used to end a transmission)
|   |         $6D : Send screendump
|   |                                      Low byte
|   |   Data word / Size of DataPart       |  High byte
|   |   |     Data zero or more bytes      |  |
|-- |-- |---- |-----------------           |- |-
$85 $56 00 00 [DataPart:00 .. 00 Checksum: 00 00]

Checksum=(Sum of all bytes in the datapart) and 65535

A transmission can look like this:
a variable: ABC:REAL=3.1415... (PI) from TI85 to computer (all values in hex)



          ID $85=TI85 (byte, $82 for a TI82)
          |  Command (byte): Var-header
          |  |  Packet length (word, 4+NameLength for a Var-header)
          |  |  |
          |  |  |     ------Datapart------
          |  |  |     Variable length (word)
          |  |  |     |     Type (byte 0=Real number)
          |  |  |     |     |  Name Length (byte)
          |  |  |     |     |  |  Name
          |  |  |     |     |  |  |        Checksum,(0A+03+41+42+43) and FFFF
          |- |- |---- |---- |- |- |------- |----
TI85:     85 06 07 00 0A 00 00 03 41 42 43 D3 00
COMPUTER:                                        05 56 00 00
                                                 |- |- |----
                                                 |  |  No packet
                                                 |  Command: Received OK
                                                 ID $05 = Computer <=> TI85
                                                    ($02 = Computer <=> TI82)
                         Received OK
                         |           Command: Data part
                         |           |  Packet length: 10 bytes for a REAL
                         |           |  |     Data (PI)
                         |-          |- |---- |----------------------------
TI85:                 85 56 00 00 85 15 0A 00 00 00 FC 31 41 59 26 53 58 98
COMPUTER: 05 09 00 00
             |- |----
             |  No packet
             Command: Ready to receive data part

          Checksum             Command: No more variables
          |                    |  10 bytes data was sent
          |----                |- |----
TI85:     30 03             85 92 0A 00             "Done..."
COMPUTER:       05 56 00 00             05 56 00 00 END
                   |-                      |-
                   Received OK             Received OK



If a TI82 is used instead of a TI85, the Var-header command changes:
1. The "Type" byte - TI82/TI85 have different variable types
2. The "Name length" byte - don't exists for the TI82. The name is Zero-
   terminated.

Example: the variable ABC on a TI82 (header command):
82 06 07 00 0A 00 00 41 42 43 00 D0 00
                     |------- |-
                     Name     Zero - terminates the string


After a Var-header have been sent, then the calculator (or computer) waits
for a "Received OK"-command and an answer. The answer can be one of the
following (the computer sends, TI85 receives and answers) :

85 09 07 00          : Continue (header-datalength: 7 bytes)
85 5A 07 00          : Checksum error, send last package again
The two following answers can occur if the variable already exists in memory:
85 36 01 00 02 02 00 : Variable skipped ("Skip" was pressed)
85 36 01 00 01 01 00 : Variable refused ("Exit" was pressed)

If more than one variable is send, then a "Var-header" command when the
reciever (calculator or computer),have acknowledged the datapackage instead
of a "No more variables"-command.

The "Type"-byte (for a TI85) can have one of the following values (hex):
00    Real
01    Cplx
02    Vectr  03  Vectr complex
04    List   05  List  complex
06    Matrx  07  Matrx complex
08    Const  09  Const complex
0A    Equ
0B    Range
0C    Strng
0D-10 GDB
11    Pict
12    Prgm
13    Range
14    ?
15-1B Range

I'm not sure everything's alright about the TI82 because I just borrowed one
for a weekend. But if anyone can figure out more about the TI82 and the 
CBL-format (for both TI82 & TI85), send me a note.

Note:
The "Send screendump" command can be sent to the TI85/TI82 to download
a screendump to the computer. The TI85/TI82 will send a "Received Ok"-command
and the a datapackage of 1024 bytes. The datapackage is a copy of the
memoryarea $FC00-FFFF (the screen). This works almost anytime (it's not
necessary the calculator is in the LINK-menu), but it won't work when a
program is running (except if the program is waiting for a key).


****** Procedure to set/reset RTS/DTR:

 procedure SetPort(Bits:Byte);
 { Input: "Bits", a byte 0 - 3, bit 0 = DTR, bit 1 = RTS }

 begin
   Port[PortAddr+4]:=Bits and 3;
 end;

****** Function to read CTS/DSR:

 function  GetPort:Byte;
 { Returns a byte 0 - 3, bit 0 = CTS, bit 1 = DSR }
 { if GetPort returns 0, then the calculator have noticed a timeout }

 begin
   GetPort:=(Port[PortAddr+6] and 48) div 16;
   { if KeyPressed then HALT(1); }
   { Add the line above if you don't add a timeout-check somewhere else. }
   { The program will probably hang in "GetPort" when the calculator     }
   { causes a Timeout }
 end;

****** To send a byte to the TI85/TI82:

 procedure Send(B:Byte);
 { Sends the byte B to the calculator }

 var
    BitLoop:Byte;

 begin
   { Send the bits from bit 0 -> bit 7 }
   SetPort(3);
   for BitLoop:=0 to 7 do begin
       { Wait for calculator to be ready to recieve a bit }
       { RTS and DTR must be set }
     while GetPort<>3 do;
     if (B and 1)=0 then begin
          { Send 0 : DTR=1, DSR=0 }
        SetPort(1);
          { Wait for calculator to set RTS=1 }
        while (GetPort and 2)=2 do;
          { CTS=1, DSR=1 }
        SetPort(3);
          { Wait for calculator to set RTS=0 }
        while (GetPort and 2)=0 do;
     end else begin
          { Send 1 : CTS=0, DSR=1 }
        SetPort(2);
          { Wait for calculator to set DTR=1 }
        while (GetPort and 1)=1 do;
          { CTS=1, DSR=1 }
        SetPort(3);
          { Wait for calculator to set DTR=0 }
        while (GetPort and 1)=0 do;
     end;
     B:=B div 2;
   end;
 end;

****** To recieve a byte from the TI85/TI82:

 function Receive:Byte;
 { Recieves a byte from calculator }

 var
    B,CurrentBit,BitLoop:Byte;

 begin
   CurrentBit:=1;
   B:=0;
   { Recieve bit 0 first }
   SetPort(3);
   for BitLoop:=0 to 7 do begin
       { Wait for the calculator to send a bit }
     while GetPort=3 do;
       { Check it the calculator sends a 1 or 0 }
     if GetPort=1 then begin
        { 1 }
        B:=B or CurrentBit;
          { CTS=1, DSR=0 }
        SetPort(1);
          { Wait while RTS=0 }
        while (GetPort and 2)=0 do;
     end else begin
        { 0 }
          { CTS=0, DSR=1 }
        SetPort(2);
          { Wait while DTR=0 }
        while (GetPort and 1)=0 do;
     end;
       { CTS=1, DSR=1 }
     SetPort(3);
       { Wait for calculator to set RTS & DTR }
     while GetPort<>3 do;
     CurrentBit:=CurrentBit*2;
   end;
   Receive:=B;
 end;

****** Initiates the com-port (MUST be called before anything else)

 procedure InitPort;

 begin
   Port[PortAddr+1]:=0;
   Port[PortAddr+2]:=1;
   Port[PortAddr+3]:=0;
   Port[PortAddr+4]:=3;
   Port[PortAddr+5]:=96;
   Port[PortAddr+6]:=50;
   Port[PortAddr+7]:=0;
      { Set CTS & DSR }
   SetPort(3);
 end;


--------------------------
Per Finander
e-mail:pfimdt93@hvdc.hv.se
